home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Light ROM 1
/
LIGHT-ROM 1 (Amiga Library Services)(1994).iso
/
ffdisks
/
d939.lha
/
ExtraCmds
/
source_etc.lha
/
src
/
Split.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-22
|
9KB
|
343 lines
/* --------------------------------- -------
* |\ | | | | | |.| | \| |/ /|\ |||||||
* | | | |/ | |\ |/ |/| |\ |/ | ? ---+--- =<
* | | | | | | | | | | | \qqqqqqqqq/
* --------------------------------- ~~~~~~~~~~~~~~~~
* Split - Split a file into pieces.
* Copyright (C) 1989, 1992, 1993 Torsten Poulin
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public Licence as published by
* the Free Software Foundation; either version 2 of the Licence, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public Licence for more details.
*
* You should have received a copy of the GNU General Public Licence
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* The author can be contacted by s-mail at
* Torsten Poulin
* Banebrinken 99, 2, 77
* DK-2400 Copenhagen NV
* DENMARK
*
* $Id: Split.c,v 37.5 93/03/30 23:12:33 Torsten Rel $
* $Log: Split.c,v $
* Revision 37.5 93/03/30 23:12:33 Torsten
* Rewritten from scratch. The code is a lot easier to maintain
* and improve now. An informal test showed that byte oriented
* splits (BYTES and PARTS) are approx. 10-35 times faster than before.
* The line oriented mode hasn't been optimized yet.
* The price to be paid is an 80% bigger executable (still smaller
* than 2kb though ;-).
* The 28 character limit on the TO name has been raised to 253.
* Important: The template has been changed!!!
*
* Revision 37.4 93/02/13 16:13:10 Torsten
* Replaced exec.library/SetSignal() with dos.library/CheckSignal().
*
*/
#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <dos/dostags.h>
#include <clib/macros.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#ifdef __SASC
#include <pragmas/dos_pragmas.h>
#include <pragmas/exec_pragmas.h>
#endif
#include <string.h>
#include "tastlib.h"
#include "split_rev.h"
#define SPLITBUFSIZE 51200L
#define PROGNAME "Split"
#define TEMPLATE "FROM,TO/K,LINES/K/N,BYTES/K/N,PARTS/K/N,PROMPT/S"
#define OPT_FROM 0
#define OPT_TO 1
#define OPT_LINES 2
#define OPT_BYTES 3
#define OPT_PARTS 4
#define OPT_PROMPT 5
typedef struct {
struct DosLibrary *DOSBase;
struct FileInfoBlock fib;
BOOL prompt;
LONG type;
LONG number;
UBYTE outname[256], *ext2, *ext1;
/* a future version will automatically try smaller buffers if necessary */
UBYTE buffer[SPLITBUFSIZE];
LONG bufsize;
} Global;
char const versionID[] = VERSTAG;
char const copyright[] = "$COPYRIGHT:©1989,1992,1993 Torsten Poulin$";
LONG getnumber(LONG);
VOID initoutname(UBYTE *, Global *);
VOID incoutname(Global *);
LONG split(BPTR, Global *);
LONG copylines(BPTR, BPTR, LONG, Global *);
LONG copybytes(BPTR, BPTR, LONG, Global *);
VOID promptuser(Global *);
LONG entrypoint(VOID)
{
struct DosLibrary *DOSBase;
struct RDArgs *args;
Global *global;
LONG arg[6];
LONG rc = RETURN_OK;
BPTR input;
if (!(DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37L)))
return RETURN_FAIL;
if (!(global = AllocVec(sizeof(Global), MEMF_CLEAR)))
rc = ERROR_NO_FREE_STORE;
else
{
global->DOSBase = DOSBase;
global->bufsize = SPLITBUFSIZE;
arg[OPT_FROM] = arg[OPT_TO] = arg[OPT_LINES] =
arg[OPT_PARTS] = arg[OPT_BYTES] = arg[OPT_PROMPT] = 0L;
if (!(args = ReadArgs(TEMPLATE, arg, NULL)))
rc = RETURN_FAIL;
else
{
initoutname(arg[OPT_TO] ? (UBYTE *) arg[OPT_TO] : "x", global);
global->prompt = (BOOL) arg[OPT_PROMPT];
if (arg[OPT_PARTS])
{
global->type = OPT_PARTS;
global->number = getnumber(arg[OPT_PARTS]);
}
else if (arg[OPT_BYTES])
{
global->type = OPT_BYTES;
global->number = getnumber(arg[OPT_BYTES]);
}
else if (arg[OPT_LINES])
{
global->type = OPT_LINES;
global->number = getnumber(arg[OPT_LINES]);
}
else
{
global->type = OPT_LINES;
global->number = 1000;
}
if (!arg[OPT_FROM])
rc = split(Input(), global);
else if (input = Open((UBYTE *) arg[OPT_FROM], MODE_OLDFILE))
{
rc = split(input, global);
Close(input);
}
else
rc = RETURN_ERROR;
FreeArgs(args);
}
FreeVec(global);
}
rc = printErrorMsg(rc, PROGNAME, DOSBase);
CloseLibrary((struct Library *) DOSBase);
return rc;
}
LONG getnumber(LONG val)
{
LONG number;
number = *(ULONG *) val;
if (number < 1L)
number = 1L;
return number;
}
VOID initoutname(UBYTE *name, Global *global)
{
UBYTE *p = global->outname;
LONG len;
for (len = 0; *name && len < 253; len++, name++)
*p++ = *name;
global->ext1 = p;
*p++ = 'a';
global->ext2 = p;
*p++ = 'a';
*p = '\0';
}
VOID incoutname(Global *global)
{
if (*global->ext2 < 'z')
++*global->ext2;
else
{
*global->ext2 = 'a';
++*global->ext1;
}
}
LONG split(BPTR input, Global *global)
{
struct DosLibrary *DOSBase = global->DOSBase;
LONG (*copy)(BPTR in, BPTR out, LONG number, Global *global);
LONG rc = RETURN_OK;
LONG count = 0;
BPTR output;
if (global->type == OPT_PARTS)
{
/* To use PARTS we obviously need to know how long the file is.
* Previous versions of this program used Seek() to determine the
* length. This led to very unhappy results if the input happened
* to be a pipe. In my humble opinion pipes either shouldn't
* support the ACTION_SEEK packet, or better when supporting
* ACTION_EXAMINE_OBJECT should set the fib_DirEntryType to
* something like ST_PIPE or whatever (to be honest the various
* pipe handlers I have actually do that: William Hawes' PIP: sets
* it to -5. C-A's PIPE: and Matt Dillon's FIFO: set it to 0).
* How about creating an official (documented) standard? So given
* the present circumstances the following, though not without its
* flaws, works a little better.
*/
if (!ExamineFH(input, &global->fib)
|| global->fib.fib_Size == 0
|| global->fib.fib_DirEntryType == -5
|| global->fib.fib_DirEntryType == 0)
{
MyPrintf(global,
"%s: Cannot determine size (file is a pipe or empty)\n",
PROGNAME);
SetIoErr(ERROR_OBJECT_WRONG_TYPE);
return RETURN_ERROR;
}
else
{
if (global->number > 676)
global->number = 676;
global->number = global->fib.fib_Size / global->number + 1;
}
}
if (global->type == OPT_LINES)
copy = copylines;
else
copy = copybytes;
while (rc == RETURN_OK)
{
count++;
if (count == 676)
global->number = -1;
if (global->prompt)
promptuser(global);
if (!(output = Open(global->outname, MODE_NEWFILE)))
{
MyPrintf(global, "%s: Cannot open %s\n", PROGNAME, global->outname);
return RETURN_ERROR;
}
rc = copy(input, output, global->number, global);
Close(output);
incoutname(global);
}
if (rc == EOF)
rc = RETURN_OK;
return rc;
}
LONG copylines(BPTR in, BPTR out, LONG number, Global *global)
{
struct DosLibrary *DOSBase = global->DOSBase;
register UBYTE breakcheck = 0;
LONG count = 0;
LONG c;
while ((c = FGetC(in)) != EOF)
{
if (FPutC(out, c) == EOF)
return RETURN_ERROR;
if (c == '\n')
{
count++;
if (count == number)
return RETURN_OK;
}
if (!(breakcheck -= 4) && CheckSignal(SIGBREAKF_CTRL_C))
return ERROR_BREAK;
}
return EOF;
}
LONG copybytes(BPTR in, BPTR out, LONG number, Global *global)
{
struct DosLibrary *DOSBase = global->DOSBase;
LONG wrote, read;
LONG bytes;
BOOL to_end = number < 0;
bytes = to_end ? global->bufsize : MIN(global->bufsize, number);
wrote = 1;
while ((read = Read(in, global->buffer, bytes)) > 0 && wrote > 0)
{
wrote = Write(out, global->buffer, read);
if (!to_end)
{
if ((number -= read) == 0)
break;
bytes = MIN(global->bufsize, number);
}
if (CheckSignal(SIGBREAKF_CTRL_C))
return ERROR_BREAK;
}
if (read < 0 || wrote < 0)
return RETURN_ERROR;
else if (read == 0)
return EOF;
else
return RETURN_OK;
}
VOID promptuser(Global *global)
{
struct DosLibrary *DOSBase = global->DOSBase;
BPTR console;
MyPrintf(global, "Press RETURN to write %s", global->outname);
Flush(Output());
if (console = Open("CONSOLE:", MODE_OLDFILE))
{
FGetC(console);
Close(console);
}
}